import logging
import os
import threading
import time
import serial

from detecter import settings
from api import models, utils
from api.serial.data import SocketResponse, UIResult
from api.webRequest import assign

logger = logging.getLogger('serial.listener')


class SampleListener(threading.Thread):
    __instance = None

    def __init__(self, port, baud, label_frame_size, voltage_frame_size, current_mould):
        super().__init__()
        self.setName('sample_listener')
        self.__running = threading.Event()
        self.__label_frame_size = label_frame_size  # 8  # listener线程采用的通信协议的一个周期的数据帧长度
        self.__voltage_frame_size = voltage_frame_size  # 9  # listener线程采集电压帧的长度
        self.__port = serial.Serial(port, baud)
        self.current_mould = current_mould

    @classmethod
    def new_instance(cls, current_mould):
        cls.__instance = SampleListener(settings.PORT_LISTEN, settings.BAUD_RATE_LISTEN,
                                        settings.LABEL_FRAME_SIZE, settings.VOLTAGE_FRAME_SIZE,
                                        current_mould)
        return cls.__instance

    @classmethod
    def get_instance(cls):
        return cls.__instance

    def is_listener_running(self):
        return self.__running.is_set()

    def begin(self):
        if not self.is_alive():
            self.__running.set()
            self.__port.close()
            if not self.__port.isOpen():
                self.__port.open()
            self.setDaemon(False)  # 不设置守护线程, 就算websocket挂了也继续监听, 直到停止本工单才算停止此线程
            self.start()

    def stop(self):
        if self.is_alive():
            self.__running.clear()  # 设置为False
            logger.warning('listener线程准备退出')
        else:
            logger.warning('listener线程不在工作中')

    def run(self):
        self.__port.close()
        current_mould = self.current_mould
        if not self.__port.isOpen():
            try:
                self.__port.open()
            except:
                logger.info("listener线程串口无法打开，请检查串口设备号")
        label_size = self.__label_frame_size
        voltage_size = self.__voltage_frame_size
        while self.__running.is_set():
            count = self.__port.inWaiting()
            temp_bytes = self.__port.read(count)
            if len(temp_bytes) >= label_size:
                logger.info("listener received data!")
                frame_bytes = temp_bytes[0:label_size]
                if self.is_label_frame(frame_bytes):
                    current_sample = self.current_mould.prod_sample
                    label_id = int(frame_bytes[5]) + 2 if frame_bytes[5] <= 0x09 else 1
                    logger.info(f"监听到打标签请求， 按键值数据{label_id}, 当前样本id为{current_sample.id}")
                    data = {
                        "sample_result":
                            {"sample_id": current_sample.id, "label_id": label_id, "reason_id": 1}
                        ,
                        "time": ""
                    }
                    try:
                        db_mould = models.Mould.objects.filter(mould_code=
                                                               self.current_mould.mould_code)[0]
                    except Exception as e:
                        logger.info("数据库缺少当前生产的工单数据")
                        logger.error(str(e))
                    try:
                        assign.assign_sample(db_mould=db_mould, mode="assign", data=data)
                    except Exception as e:
                        logger.error(str(e))
                elif len(temp_bytes) >= voltage_size and self.is_voltage_frame(temp_bytes[0:voltage_size]):
                    current_voltage = int(temp_bytes[4]) * 256 + int(temp_bytes[5])
                    logger.info(f"当前打标签模块的电压值为: {current_voltage}")
                    if current_voltage <= 5500:
                        logger.info("*" * 15 + " 提醒 " + "*" * 15)
                        logger.info("  打标签模块电压小于5.5V，请充电！ ")
                        current_mould.websocket.msg_send(SocketResponse.error("\n  打标签模块电压小于5.5V，请充电！ "))
                        logger.info("*" * 36)
                else:
                    logger.error('数据校验出错: %s' % utils.bytes2hex(frame_bytes))

    @staticmethod
    def is_label_frame(unknown_bytes):
        check_bytes = unknown_bytes[1:6]
        check_result = unknown_bytes[6]
        if unknown_bytes[0] == 0xAA and unknown_bytes[1] == 0xff and unknown_bytes[3] == 0x06 \
                and unknown_bytes[4] == 0x03 and unknown_bytes[7] == 0xAA:
            bbc = 0x00  # 0异或任何数为任何数本身
            for byte in check_bytes:
                bbc ^= byte
            return bbc == check_result
        else:
            return False

    @staticmethod
    def is_voltage_frame(unknown_bytes):
        check_bytes = unknown_bytes[1:7]
        check_result = unknown_bytes[7]
        if unknown_bytes[0] == 0xAA and unknown_bytes[1] == 0xff and unknown_bytes[3] == 0x07 \
                and unknown_bytes[4] == 0x04 and unknown_bytes[8] == 0xAA:
            bbc = 0x00  # 0异或任何数为任何数本身
            for byte in check_bytes:
                bbc ^= byte
            return bbc == check_result
        else:
            return False
